#include "global_declarations.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "stdio.h"
#include "assert.h"
#include "misc.h"

/**
 * initializes the String size.
 * @postcondition: dest->size = size.
 * @precondition: must be performed after make_empty string.
 */
void String_init(String* dest, int size) {
	dest->data = calloc(size + 1, 1);
	dest->size = size;
}

/**
 * creates an empty String.
 */
String* make_empty_string() {
	String* s = calloc(1, sizeof(String));
	s->data = 0;
	s->size = 0;
	return s;
}

String* make_string_from_char_arr(char* s) {
	String* str = make_empty_string();
	String_copy(str, s);
	return str;
}

/**
 * prints the string's data to standard output.
 */
void String_print(String* str) {
	printf("%s", str->data);
}

/**
 * copys an array of chars to dest.
 * @precondition: dest must be initialized and empty.
 */
void String_copy(String* dest, char* src) {
	int64 l;
	l = strlen(src);
	String_init(dest, l);
	strcpy(dest->data, src);
}

/**
 * copys first n bytes of an array of chars to dest.
 * @precondition: dest must be initialized and empty.
 */
void String_n_copy(String* dest, char* src, int n) {
	dest->data = calloc(n + 1, 1);
	memcpy(dest->data, src, n);
	dest->size = n;
}

/**
 * frees the String s.
 */
void String_free(String* s) {
	if (s->data != 0)
		free(s->data);
	s->size = 0;
	free(s);
}

/**
 *resets the data within str.
 */
void String_reset(String* str) {
	if (str->data != 0)
		free(str->data);
	str->data = 0;
	str->size = 0;
}

/**
 * concatenates src to dest.
 * @precondition: dest must be initialized.
 */
void String_cat(String* dest, char* src) {
	int64 ld, ls;
	ld = dest->size;
	if (src == 0)
		return;
	ls = strlen(src);
	dest->data = realloc(dest->data, ld + ls + 1);
	memset(dest->data + ld, 0, ls + 1);
	strcat(dest->data, src);
	dest->size += ls;
}

/**
 * concatenates src to dest.
 * @precondition: dest must be initialized.
 */
void String_cat_String(String* dest, String* src) {
	assert (src != NULL);
	String_cat(dest, src->data);
}

/**
 * copies the data within src to dest.
 * @precondition: dest must be initialized.
 */
void String_copy_string(String* dest, String* src) {
	assert (src != NULL);
	String_copy(dest, src->data);
}

/**
 * puts i as a digit in dest.
 * @precondition: 0 < i <10.
 * @precondition: dest must be initialized.
 * @post: dest->size = 1, dest->data = "i".
 */
void int_to_string_digit(String* dest, int i) {
	String_init(dest, 1);
	dest->data[0] = '0' + i;
}


/**
 * puts i's as a English letter in dest (0 = a, 1 = b, 26 = A, 27 = B).
 * @precondition: 0 < i < 52.
 * @precondition: dest must be initialized.
 */
void char_int_to_string(String* dest, int i) {
	dest->data = calloc(2, 1);
	dest->size = 1;
	if (i < 26)
		dest->data[0] = 'a' + i;
	else
		dest->data[0] = 'A' + i - 26;
}

/**
 * flips the case of the char: a => A, A => a.
 */
char flip_char_case(char c) {
	int ci = (int) c;
	if (islower(ci))
		return toupper(ci);
	return tolower(ci);
}

/**
 * checks whether s represents a number.
 */
bool is_number(char* s) {
	char* cur;
	if (s == NULL)
		return false;
	cur = s;
	if (*cur == 0)
		return false;
	while (*cur != 0) {
		if (!isdigit((int)*cur))
			return false;
		cur++;
	}
	return true;
}

/**
 * returns the int64 value of the strings data.
 * @precondition: is_number(s.data) == true
 */
int64 String_to_int64(String s) {
	int64 sum;
	int i, l;
	l = s.size;
	sum = 0;
	for (i = 0; i < l; ++i)
		sum = sum * 10 + (s.data[i] - '0');
	return sum;
}

/**
 * returns the minimum int between the two.
 */
int min_int(int a, int b) {
	return a > b ? b : a;
}

/**
 * returns the maximum int between the two.
 */
int max_int(int a, int b) {
	return a > b ? a : b;
}

/**
 * removes the "\n" at the end of the gives char*.
 */
void remove_end_of_line(char* str) {
	int i;
	for (i = 0; i < MAX_LINE_LENGTH; ++i) {
		if (str[i] == 0)
			return;
		if (str[i] == '\n') {
			str[i] = 0;
			return;
		}
	}
}
